home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / hack / 3_1 / util / makedefs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-21  |  44.0 KB  |  1,919 lines

  1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  2. /* Copyright (c) M. Stephenson, 1990, 1991.              */
  3. /* Copyright (c) Dean Luick, 1990.                  */
  4. /* NetHack may be freely redistributed.  See license for details. */
  5. /* makedefs.c - NetHack version 3.1 */
  6.  
  7. #define    MAKEDEFS_C    /* use to conditionally include file sections */
  8. /* #define DEBUG /* uncomment for debugging info */
  9.  
  10. #include "config.h"
  11. #include "permonst.h"
  12. #include "objclass.h"
  13. #include "monsym.h"
  14. #include "artilist.h"
  15.  
  16. #ifdef MAC
  17. # ifdef applec    /* Means the MPW compiler, I hope */
  18. #  define MPWTOOL
  19. #  include <CursorCtl.h>
  20. # else        /* MAC without MPWTOOL */
  21. #  define MACsansMPWTOOL
  22. # endif
  23. #include <string.h>
  24. #include <ctype.h>
  25. #endif /* MAC */
  26.  
  27. #ifndef MPWTOOL
  28. # define SpinCursor(x)
  29. #endif
  30.  
  31. #define Fprintf    (void) fprintf
  32. #define Fclose    (void) fclose
  33. #define Unlink    (void) unlink
  34. #if !defined(AMIGA) || defined(AZTEC_C)
  35. #define rewind(fp) fseek((fp),0L,SEEK_SET)    /* guarantee a return value */
  36. #endif
  37.  
  38. #ifdef NULL
  39. #undef NULL
  40. #endif
  41. #define NULL    ((char *)0)
  42.  
  43. #if !defined(LINT) && !defined(GCC_WARN)
  44. static    const char    SCCS_Id[] = "@(#)makedefs.c\t3.1\t93/01/20";
  45. #endif
  46.  
  47. #ifdef MICRO
  48. # undef    exit
  49. extern void FDECL(exit, (int));
  50. #endif
  51.  
  52. #define WRMODE  "w+"
  53. #define RDMODE  "r"
  54. /* the quest.dat file is binary, while everything else is text... */
  55. #if defined(MICRO) && !defined(AMIGA)
  56. # define WRBMODE "w+b"
  57. #else
  58. # define WRBMODE "w+"
  59. #endif
  60.  
  61. #ifndef SEEK_SET
  62. # define SEEK_SET 0
  63. #endif
  64. #ifndef SEEK_END
  65. # define SEEK_END 2
  66. #endif
  67.  
  68.     /* names of files to be generated */
  69. #define DATE_FILE    "date.h"
  70. #define MONST_FILE    "pm.h"
  71. #define ONAME_FILE    "onames.h"
  72. #define OPTIONS_FILE    "options"
  73. #define ORACLE_FILE    "oracles"
  74. #define DATA_FILE    "data"
  75. #define RUMOR_FILE    "rumors"
  76. #define DGN_I_FILE    "dungeon.def"
  77. #define DGN_O_FILE    "dungeon.pdf"
  78. #define MON_STR_C    "monstr.c"
  79. #define QTXT_I_FILE    "quest.txt"
  80. #define QTXT_O_FILE    "quest.dat"
  81. #define VIS_TAB_H    "vis_tab.h"
  82. #define VIS_TAB_C    "vis_tab.c"
  83.     /* locations for those files */
  84. #ifdef AMIGA
  85. # define INCLUDE_TEMPLATE    "Incl:t.%s"
  86. # define SOURCE_TEMPLATE    "NHS:%s"
  87. # define DATA_TEMPLATE        "Dat:%s"
  88. #else
  89. # ifdef MAC
  90. #   define INCLUDE_TEMPLATE    ":include:%s"
  91. #   define SOURCE_TEMPLATE    ":src:%s"
  92. #   define DATA_TEMPLATE    ":dat:%s"
  93. # else /* MAC */
  94. #   define INCLUDE_TEMPLATE    "../include/%s"
  95. #   define SOURCE_TEMPLATE    "../src/%s"
  96. #   define DATA_TEMPLATE    "../dat/%s"
  97. # endif /* MAC */
  98. #endif    /* AMIGA */
  99.  
  100. static const char
  101.     *Dont_Edit_Code =
  102.     "/* This source file is generated by 'makedefs'.  Do not edit. */\n",
  103.     *Dont_Edit_Data =
  104.     "#\tThis data file is generated by 'makedefs'.  Do not edit. \n";
  105.  
  106. /* definitions used for vision tables */
  107. #define TEST_WIDTH  COLNO
  108. #define TEST_HEIGHT ROWNO
  109. #define BLOCK_WIDTH (TEST_WIDTH + 10)
  110. #define BLOCK_HEIGHT TEST_HEIGHT    /* don't need extra spaces */
  111. #define MAX_ROW (BLOCK_HEIGHT + TEST_HEIGHT)
  112. #define MAX_COL (BLOCK_WIDTH + TEST_WIDTH)
  113. /* Use this as an out-of-bound value in the close table.  */
  114. #define CLOSE_OFF_TABLE_STRING "99,"    /* for the close table */
  115. #define FAR_OFF_TABLE_STRING "0xff,"    /* for the far table */
  116.  
  117. #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0))
  118. #ifdef VISION_TABLES
  119. static char xclear[MAX_ROW][MAX_COL];
  120. #endif
  121. /*-end of vision defs-*/
  122.  
  123. static char    in_line[256], filename[30];
  124.  
  125. #ifdef MACsansMPWTOOL
  126. void FDECL(macstart, (void));
  127. int FDECL(main, (void));
  128. #else
  129. int FDECL(main, (int, char **));
  130. #endif
  131. int FDECL(do_makedefs, (int, char **));
  132. void NDECL(do_objs);
  133. void NDECL(do_data);
  134. void NDECL(do_dungeon);
  135. void NDECL(do_date);
  136. void NDECL(do_options);
  137. void NDECL(do_monstr);
  138. void NDECL(do_permonst);
  139. void NDECL(do_questtxt);
  140. void NDECL(do_rumors);
  141. void NDECL(do_oracles);
  142. void NDECL(do_vision);
  143.  
  144. extern void NDECL(monst_init);        /* monst.c */
  145. extern void NDECL(objects_init);    /* objects.c */
  146.  
  147. static char *FDECL(xcrypt, (const char *));
  148. static int FDECL(check_control, (char *));
  149. static char *FDECL(without_control, (char *));
  150. static boolean FDECL(d_filter, (char *));
  151. static boolean FDECL(h_filter, (char *));
  152. static boolean FDECL(ranged_attk,(struct permonst*));
  153. static int FDECL(mstrength,(struct permonst *));
  154.  
  155. #ifdef MULDGN
  156. static boolean FDECL(qt_comment, (char *));
  157. static boolean FDECL(qt_control, (char *));
  158. static int FDECL(get_hdr, (CHAR_P));
  159. static boolean FDECL(known_id, (CHAR_P));
  160. static boolean FDECL(new_id, (CHAR_P));
  161. static boolean FDECL(known_msg, (CHAR_P, char *));
  162. static void FDECL(new_msg, (char *));
  163. static void FDECL(do_qt_control, (char *));
  164. static void FDECL(do_qt_text, (char *));
  165. static void NDECL(adjust_qt_hdrs);
  166. static void NDECL(put_qt_hdrs);
  167. #endif
  168.  
  169. #ifdef VISION_TABLES
  170. static void NDECL(H_close_gen);
  171. static void NDECL(H_far_gen);
  172. static void NDECL(C_close_gen);
  173. static void NDECL(C_far_gen);
  174. static int FDECL(clear_path, (int,int,int,int));
  175. #endif
  176.  
  177. char * FDECL(tmpdup, (const char *));
  178. char * FDECL(limit, (char *,int));
  179.  
  180. /* input, output, tmp */
  181.  
  182. FILE    *ifp, *ofp, *tfp;
  183.  
  184. #ifdef MACsansMPWTOOL
  185. char mac_opt;
  186.  
  187. void
  188. macstart()
  189. {
  190.     static char buf[100];
  191.     static char *ptr = NULL;
  192.  
  193. again :
  194.     if (!ptr || !*ptr) {
  195.         Fprintf(stderr, "Options: otdemvpqrhz\n");
  196.         buf[0] = 0;
  197.         fgets(buf, 100, stdin);
  198.         ptr = buf;
  199.     }
  200.  
  201.     do {
  202.         mac_opt = *ptr++;
  203.     } while (mac_opt && isspace(mac_opt));
  204.  
  205.     if (!mac_opt) {
  206.         Fprintf(stderr, "Makedefs done.\n");
  207.         exit(0);
  208.     }
  209. }
  210. #endif /* MAC */
  211.  
  212.  
  213. int
  214. #ifdef MACsansMPWTOOL
  215. main(void)
  216. {
  217.     int argc;
  218.     char **argv;
  219. #else /* ! MAC */
  220. main(argc, argv)
  221. int    argc;
  222. char    *argv[];
  223. {
  224. #endif /* MAC */
  225.     /* Note:  these initializers don't do anything except guarantee that
  226.         we're linked properly.
  227.     */
  228.     monst_init();
  229.     objects_init();
  230.  
  231. #ifdef MACsansMPWTOOL
  232.     while (1) {
  233.         macstart();
  234.         do_makedefs(argc, argv);
  235.     }
  236. #else
  237.     if (do_makedefs(argc, argv))
  238.         exit(1);
  239. #endif
  240. #ifndef VMS
  241.     return 0;
  242. #else
  243.     return 1;       /* vms success */
  244. #endif /*VMS*/
  245. }
  246.  
  247. int
  248. do_makedefs(arrgc, arrgv)
  249. int    arrgc;
  250. char    *arrgv[];
  251. {
  252. #ifdef MACsansMPWTOOL
  253.     if (1) {
  254.         Fprintf(stderr, "makedefs -%c\n", mac_opt);
  255.         switch (mac_opt) {
  256. #else /* !MAC */
  257.     if (arrgc == 2) {
  258.         char *option = arrgv[1];
  259.         switch (option[1]) {
  260. #endif /* MAC */
  261.         case 'o':
  262.         case 'O':    do_objs();
  263.                 break;
  264.         case 't':            /* this may go away... */
  265.         case 'T':    Fprintf(stderr,    "`-t' option is obsolete.\n");
  266.                 break;
  267.         case 'd':
  268.         case 'D':    do_data();
  269.                 break;
  270.         case 'e':
  271.         case 'E':    do_dungeon();
  272.                 break;
  273.         case 'm':
  274.         case 'M':    do_monstr();
  275.                 break;
  276.         case 'v':
  277.         case 'V':    do_date();
  278.                 do_options();
  279.                 break;
  280.         case 'p':
  281.         case 'P':    do_permonst();
  282.                 break;
  283.         case 'q':
  284.         case 'Q':    do_questtxt();
  285.                 break;
  286.         case 'r':
  287.         case 'R':    do_rumors();
  288.                 break;
  289.         case 'h':
  290.         case 'H':    do_oracles();
  291.                 break;
  292.         case 'z':
  293.         case 'Z':    do_vision();
  294.                 break;
  295.  
  296.         default:
  297.                 Fprintf(stderr,    "Unknown option '%c'.\n",
  298. #ifdef MACsansMPWTOOL
  299.                     mac_opt
  300. #else /* MAC */
  301.                     option[1]
  302. #endif /* MAC */
  303.                     );
  304.                 (void) fflush(stderr);
  305.                 return(1);
  306.         }
  307.         return 0;
  308.     } else {
  309.         Fprintf(stderr, "Bad arg count (%d).\n", arrgc-1);
  310.         (void) fflush(stderr);
  311.         return 1;
  312.     }
  313. }
  314.  
  315.  
  316. /* trivial text encryption routine which can't be broken with `tr' */
  317. static
  318. char *xcrypt(str)
  319. const char *str;
  320. {                /* duplicated in src/hacklib.c */
  321.     static char buf[BUFSZ];
  322.     register const char *p;
  323.     register char *q;
  324.     register int bitmask;
  325.  
  326.     for (bitmask = 1, p = str, q = buf; *p; q++) {
  327.         *q = *p++;
  328.         if (*q & (32|64)) *q ^= bitmask;
  329.         if ((bitmask <<= 1) >= 32) bitmask = 1;
  330.     }
  331.     *q = '\0';
  332.     return buf;
  333. }
  334.  
  335. void
  336. do_rumors()
  337. {
  338.     char    infile[30];
  339.     long    true_rumor_size;
  340.  
  341.     Sprintf(filename, DATA_TEMPLATE, RUMOR_FILE);
  342.     if (!(ofp = fopen(filename, WRMODE))) {
  343.         perror(filename);
  344.         exit(1);
  345.     }
  346.     Fprintf(ofp,Dont_Edit_Data);
  347.  
  348.     Strcat(strcpy(infile, filename), ".tru");
  349.     if (!(ifp = fopen(infile, RDMODE))) {
  350.         perror(infile);
  351.         Fclose(ofp);
  352.         Unlink(filename);    /* kill empty output file */
  353.         exit(1);
  354.     }
  355.  
  356.     /* get size of true rumors file */
  357. #ifndef VMS
  358.     (void) fseek(ifp, 0L, SEEK_END);
  359.     true_rumor_size = ftell(ifp);
  360. #else
  361.     /* seek+tell is only valid for stream format files; since rumors.%%%
  362.        might be in record format, count the actual data bytes instead.
  363.      */
  364.     true_rumor_size = 0;
  365.     while (fgets(in_line,sizeof(in_line),ifp) != NULL)
  366.         true_rumor_size += strlen(in_line);    /* includes newline */
  367. #endif /* VMS */
  368.     Fprintf(ofp,"%06lx\n", true_rumor_size);
  369.     (void) fseek(ifp, 0L, SEEK_SET);
  370.  
  371.     /* copy true rumors */
  372.     while(fgets(in_line,sizeof(in_line),ifp) != NULL)
  373.         (void) fputs(xcrypt(in_line), ofp);
  374.  
  375.     Fclose(ifp);
  376.     Strcat(strcpy(infile, filename), ".fal");
  377.     if (!(ifp = fopen(infile, RDMODE))) {
  378.         perror(infile);
  379.         Fclose(ofp);
  380.         Unlink(filename);    /* kill incomplete output file */
  381.         exit(1);
  382.     }
  383.  
  384.     /* copy false rumors */
  385.     while(fgets(in_line,sizeof(in_line),ifp) != NULL)
  386.         (void) fputs(xcrypt(in_line), ofp);
  387.  
  388.     Fclose(ifp);
  389.     Fclose(ofp);
  390.     return;
  391. }
  392.  
  393. void
  394. do_date()
  395. {
  396.     long    clocktim;
  397.     char    cbuf[30], *c;
  398.  
  399.     Sprintf(filename, INCLUDE_TEMPLATE, DATE_FILE);
  400.     if (!(ofp = fopen(filename, WRMODE))) {
  401.         perror(filename);
  402.         exit(1);
  403.     }
  404.     Fprintf(ofp,"/*\tSCCS Id: @(#)date.h\t3.1\t92/01/04 */\n\n");
  405.     Fprintf(ofp,Dont_Edit_Code);
  406.  
  407. #ifdef KR1ED
  408.     (void) time(&clocktim);
  409.     Strcpy(cbuf, ctime(&clocktim));
  410. #else
  411.     (void) time((time_t *)&clocktim);
  412.     Strcpy(cbuf, ctime((time_t *)&clocktim));
  413. #endif
  414.     for(c = cbuf; *c != '\n'; c++);    *c = 0; /* strip off the '\n' */
  415.     Fprintf(ofp,"#define BUILD_DATE \"%s\"\n", cbuf);
  416.     Fprintf(ofp,"#define BUILD_TIME (%ldL)\n", clocktim);
  417. #ifdef AMIGA
  418.     {
  419.     struct tm *tm = localtime((time_t *) &clocktim);
  420.     Fprintf(ofp,"#ifdef AMIGA\n");
  421.     Fprintf(ofp,"const char amiga_version_string[] = ");
  422.     Fprintf(ofp,"\"\\0$VER: NetHack %s (%d.%d.%d)\";\n",VERSION,tm->tm_mday,
  423.         tm->tm_mon+1,tm->tm_year);
  424.     Fprintf(ofp,"#endif\n");
  425.     }
  426. #endif
  427.     Fclose(ofp);
  428.     return;
  429. }
  430.  
  431. static const char *build_opts[] = {
  432. #ifdef AMIGA_WBENCH
  433.         "Amiga WorkBench support",
  434. #endif
  435. #ifdef ANSI_DEFAULT
  436.         "ANSI default terminal",
  437. #endif
  438. #ifdef ARMY
  439.         "armies",
  440. #endif
  441. #ifdef TEXTCOLOR
  442.         "color",
  443. #endif
  444. #ifdef COM_COMPL
  445.         "command line completion",
  446. #endif
  447. #ifdef COMPRESS
  448.         "compress bones/level/save files",
  449. #endif
  450. #ifdef ELBERETH
  451.         "Elbereth",
  452. #endif
  453. #ifdef EXP_ON_BOTL
  454.         "experience points on bottom line",
  455. #endif
  456. #ifdef EXPLORE_MODE
  457.         "explore mode",
  458. #endif
  459. #ifdef WALLIFIED_MAZE
  460.         "fancy mazes",
  461. #endif
  462. #ifdef MFLOPPY
  463.         "floppy drive support",
  464. #endif
  465. #ifdef TUTTI_FRUTTI
  466.         "fruits",
  467. #endif
  468. #ifdef KOPS
  469.         "Keystone Kops",
  470. #endif
  471. #ifdef WALKIES
  472.         "leashes",
  473. #endif
  474. #ifdef LOGFILE
  475.         "log file",
  476. #endif
  477. #ifdef MAIL
  478.         "mail daemon",
  479. #endif
  480. #ifdef MUSE
  481.         "monster item use",
  482. #endif
  483. #ifdef GNUDOS
  484.         "MSDOS protected mode",
  485. #endif
  486. #ifdef NEWS
  487.         "news file",
  488. #endif
  489. #ifdef OVERLAY
  490.         "overlays",
  491. #endif
  492. #ifdef MULDGN
  493.         "quest dungeon",
  494. #endif
  495. #ifdef REDO
  496.         "redoing commands",
  497. #endif
  498. #ifdef REINCARNATION
  499.         "rogue level",
  500. #endif
  501. #ifdef SCORE_ON_BOTL
  502.         "score on bottom line",
  503. #endif
  504. #ifdef CLIPPING
  505.         "screen clipping",
  506. #endif
  507. #ifdef SEDUCE
  508.         "seduction",
  509. #endif
  510. #ifdef POLYSELF
  511.         "self-polymorphing",
  512. #endif
  513. #ifdef SHELL
  514.         "shell command",
  515. #endif
  516. #ifdef SINKS
  517.         "sinks",
  518. #endif
  519. #ifdef SOUNDS
  520.         "sounds",
  521. #endif
  522. #ifdef SUSPEND
  523.         "suspend command",
  524. #endif
  525. #ifdef TERMINFO
  526.         "terminal info library",
  527. #else
  528. # if defined(TERMLIB) || (!defined(MICRO) && defined(TTY_GRAPHICS))
  529.         "terminal capability library",
  530. # endif
  531. #endif
  532. #ifdef TOURIST
  533.         "tourists",
  534. #endif
  535. #ifdef VISION_TABLES
  536.         "vision tables",
  537. #endif
  538. #ifdef WIZARD
  539.         "wizard mode",
  540. #endif
  541. #ifdef ZEROCOMP
  542.         "zero-compressed save files",
  543. #endif
  544.         "basic NetHack features"
  545.     };
  546.  
  547. static const char *window_opts[] = {
  548. #ifdef TTY_GRAPHICS
  549.         "traditional tty-based graphics",
  550. #endif
  551. #ifdef X11_GRAPHICS
  552.         "X11",
  553. #endif
  554. #ifdef MAC
  555.         "Mac",
  556. #endif
  557. #ifdef AMIGA_INTUITION
  558.         "Amiga Intuition",
  559. #endif
  560.         NULL
  561.     };
  562.  
  563. void
  564. do_options()
  565. {
  566.     register int i, length;
  567.     register const char *str, *indent = "    ";
  568.  
  569.     Sprintf(filename, DATA_TEMPLATE, OPTIONS_FILE);
  570.     if (!(ofp = fopen(filename, WRMODE))) {
  571.         perror(filename);
  572.         exit(1);
  573.     }
  574.      /* Fprintf(ofp,Dont_Edit_Data); */
  575.     Fprintf(ofp,"\nOptions compiled into this version of NetHack:\n");
  576.  
  577.     length = COLNO + 1;    /* force 1st item onto new line */
  578.     for (i = 0; i < SIZE(build_opts); i++) {
  579.         str = build_opts[i];
  580.         if (length + strlen(str) > COLNO - 5)
  581.         Fprintf(ofp,"\n%s", indent),  length = strlen(indent);
  582.         else
  583.         Fprintf(ofp," "),  length++;
  584.         Fprintf(ofp,"%s", str),  length += strlen(str);
  585.         Fprintf(ofp,(i < SIZE(build_opts) - 1) ? "," : "."),  length++;
  586.     }
  587.  
  588.     Fprintf(ofp,"\n\nSupported windowing systems:\n");
  589.  
  590.     length = COLNO + 1;    /* force 1st item onto new line */
  591.     for (i = 0; i < SIZE(window_opts) - 1; i++) {
  592.         str = window_opts[i];
  593.         if (length + strlen(str) > COLNO - 5)
  594.         Fprintf(ofp,"\n%s", indent),  length = strlen(indent);
  595.         else
  596.         Fprintf(ofp," "),  length++;
  597.         Fprintf(ofp,"%s", str),  length += strlen(str);
  598.         Fprintf(ofp, ","),  length++;
  599.     }
  600.     Fprintf(ofp, "\n%swith a default of %s.", indent, DEFAULT_WINDOW_SYS);
  601.     Fprintf(ofp,"\n\n");
  602.  
  603.     Fclose(ofp);
  604.     return;
  605. }
  606.  
  607. /* routine to decide whether to discard something from data.base */
  608. static boolean
  609. d_filter(line)
  610.     char *line;
  611. {
  612.     if (*line == '#') return TRUE;    /* ignore comment lines */
  613. #ifndef ARMY
  614.   { static int ignore_army = 0;
  615.  
  616.     switch (ignore_army) {
  617.       case 0:   if (!strcmp(line, "*soldier")) ignore_army = 1;
  618.         break;        /* 0 => not in army related data */
  619.       case 1:   if (*line <= ' ') ignore_army = 2;
  620.         break;        /* 1 => in army name list */
  621.       case 2:   if (*line > ' ')  ignore_army = 0;
  622.         break;        /* 2 => in army descriptive text */
  623.     }
  624.     if (ignore_army) return TRUE;
  625.   }
  626. #endif
  627.     return FALSE;
  628. }
  629.  
  630.    /*
  631.     *
  632.     New format (v3.1) of 'data' file which allows much faster lookups [pr]
  633. "do not edit"        first record is a comment line
  634. 01234567        hexadecimal formatted offset to text area
  635. name-a            first name of interest
  636. 123,4            offset to name's text, and number of lines for it
  637. name-b            next name of interest
  638. name-c            multiple names which share same description also
  639. 456,7            share a single offset,count line
  640. .            sentinel to mark end of names
  641. 789,0            dummy record containing offset,count of EOF
  642. text-a            4 lines of descriptive text for name-a
  643. text-a            at file position 0x01234567L + 123L
  644. text-a
  645. text-a
  646. text-b/text-c        7 lines of text for names-b and -c
  647. text-b/text-c        at fseek(0x01234567L + 456L)
  648. ...
  649.     *
  650.     */
  651.  
  652. void
  653. do_data()
  654. {
  655.     char    infile[30], tempfile[30];
  656.     boolean ok;
  657.     long    txt_offset;
  658.     unsigned entry_cnt, line_cnt;
  659.  
  660.     Sprintf(tempfile, DATA_TEMPLATE, "database.tmp");
  661.     Sprintf(filename, DATA_TEMPLATE, DATA_FILE);
  662.     Strcat(strcpy(infile, filename),
  663. #ifdef OS2
  664.         ".bas"
  665. #else
  666.         ".base"
  667. #endif
  668.         );
  669.     if (!(ifp = fopen(infile, RDMODE))) {        /* data.base */
  670.         perror(infile);
  671.         exit(1);
  672.     }
  673.     if (!(ofp = fopen(filename, WRMODE))) {        /* data */
  674.         perror(filename);
  675.         Fclose(ifp);
  676.         exit(1);
  677.     }
  678.     if (!(tfp = fopen(tempfile, WRMODE))) {        /* database.tmp */
  679.         perror(tempfile);
  680.         Fclose(ifp);
  681.         Fclose(ofp);
  682.         Unlink(filename);
  683.         exit(1);
  684.     }
  685.  
  686.     /* output a dummy header record; we'll rewind and overwrite it later */
  687.     Fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, 0L);
  688.  
  689.     entry_cnt = line_cnt = 0;
  690.     /* read through the input file and split it into two sections */
  691.     while (fgets(in_line, sizeof in_line, ifp)) {
  692.         if (d_filter(in_line)) continue;
  693.         if (*in_line > ' ') {    /* got an entry name */
  694.         /* first finish previous entry */
  695.         if (line_cnt)  Fprintf(ofp, "%d\n", line_cnt),  line_cnt = 0;
  696.         /* output the entry name */
  697.         (void) fputs(in_line, ofp);
  698.         entry_cnt++;        /* update number of entries */
  699.         } else if (entry_cnt) {    /* got some descriptive text */
  700.         /* update previous entry with current text offset */
  701.         if (!line_cnt)  Fprintf(ofp, "%ld,", ftell(tfp));
  702.         /* save the text line in the scratch file */
  703.         (void) fputs(in_line, tfp);
  704.         line_cnt++;        /* update line counter */
  705.         }
  706.     }
  707.     /* output an end marker and then record the current position */
  708.     if (line_cnt)  Fprintf(ofp, "%d\n", line_cnt);
  709.     Fprintf(ofp, ".\n%ld,%d\n", ftell(tfp), 0);
  710.     txt_offset = ftell(ofp);
  711.     Fclose(ifp);        /* all done with original input file */
  712.  
  713.     /* reprocess the scratch file; 1st format an error msg, just in case */
  714.     Sprintf(in_line, "rewind of \"%s\"", tempfile);
  715.     if (rewind(tfp) != 0)  goto dead_data;
  716.     /* copy all lines of text from the scratch file into the output file */
  717.     while (fgets(in_line, sizeof in_line, tfp))
  718.         (void) fputs(in_line, ofp);
  719.  
  720.     /* finished with scratch file */
  721.     Fclose(tfp);
  722.     Unlink(tempfile);    /* remove it */
  723.  
  724.     /* update the first record of the output file; prepare error msg 1st */
  725.     Sprintf(in_line, "rewind of \"%s\"", filename);
  726.     ok = (rewind(ofp) == 0);
  727.     if (ok) {
  728.        Sprintf(in_line, "header rewrite of \"%s\"", filename);
  729.        ok = (fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, txt_offset) >= 0);
  730.     }
  731.     if (!ok) {
  732. dead_data:  perror(in_line);    /* report the problem */
  733.         /* close and kill the aborted output file, then give up */
  734.         Fclose(ofp);
  735.         Unlink(filename);
  736.         exit(1);
  737.     }
  738.  
  739.     /* all done */
  740.     Fclose(ofp);
  741.  
  742.     return;
  743. }
  744.  
  745. /* routine to decide whether to discard something from oracles.txt */
  746. static boolean
  747. h_filter(line)
  748.     char *line;
  749. {
  750.     static boolean skip = FALSE;
  751.     char tag[sizeof in_line];
  752.  
  753.     SpinCursor(3);
  754.  
  755.     if (*line == '#') return TRUE;    /* ignore comment lines */
  756.     if (sscanf(line, "----- %s", tag) == 1) {
  757.     skip = FALSE;
  758. #ifndef SINKS
  759.     if (!strcmp(tag, "SINKS")) skip = TRUE;
  760. #endif
  761. #ifndef ELBERETH
  762.     if (!strcmp(tag, "ELBERETH")) skip = TRUE;
  763. #endif
  764.     } else if (skip && !strncmp(line, "-----", 5))
  765.     skip = FALSE;
  766.     return skip;
  767. }
  768.  
  769. static const char *special_oracle[] = {
  770.     "\"...it is rather disconcerting to be confronted with the",
  771.     "following theorem from [Baker, Gill, and Solovay, 1975].",
  772.     "",
  773.     "Theorem 7.18  There exist recursive languages A and B such that",
  774.     "  (1)  P(A) == NP(A), and",
  775.     "  (2)  P(B) != NP(B)",
  776.     "",
  777.     "This provides impressive evidence that the techniques that are",
  778.     "currently available will not suffice for proving that P != NP or          ",
  779.     "that P == NP.\"  [Garey and Johnson, p. 185.]"
  780. };
  781.  
  782. /*
  783.    The oracle file consists of a "do not edit" comment, a decimal count N
  784.    and set of N+1 hexadecimal fseek offsets, followed by N multiple-line
  785.    records, separated by "---" lines.  The first oracle is a special case.
  786.    The input data contains just those multi-line records, separated by
  787.    "-----" lines.
  788.  */
  789.  
  790. void
  791. do_oracles()
  792. {
  793.     char    infile[30], tempfile[30];
  794.     boolean in_oracle, ok;
  795.     long    txt_offset, offset, fpos;
  796.     unsigned oracle_cnt;
  797.     register int i;
  798.  
  799.     Sprintf(tempfile, DATA_TEMPLATE, "oracles.tmp");
  800.     Sprintf(filename, DATA_TEMPLATE, ORACLE_FILE);
  801.     Strcat(strcpy(infile, filename), ".txt");
  802.     if (!(ifp = fopen(infile, RDMODE))) {
  803.         perror(infile);
  804.         exit(1);
  805.     }
  806.     if (!(ofp = fopen(filename, WRMODE))) {
  807.         perror(filename);
  808.         Fclose(ifp);
  809.         exit(1);
  810.     }
  811.     if (!(tfp = fopen(tempfile, WRMODE))) {        /* oracles.tmp */
  812.         perror(tempfile);
  813.         Fclose(ifp);
  814.         Fclose(ofp);
  815.         Unlink(filename);
  816.         exit(1);
  817.     }
  818.  
  819.     /* output a dummy header record; we'll rewind and overwrite it later */
  820.     Fprintf(ofp, "%s%5d\n", Dont_Edit_Data, 0);
  821.  
  822.     /* handle special oracle; it must come first */
  823.     (void) fputs("---\n", tfp);
  824.     Fprintf(ofp, "%05lx\n", ftell(tfp));  /* start pos of special oracle */
  825.     for (i = 0; i < SIZE(special_oracle); i++) {
  826.         (void) fputs(xcrypt(special_oracle[i]), tfp);
  827.         (void) fputc('\n', tfp);
  828.     }
  829.     SpinCursor(3);
  830.  
  831.     oracle_cnt = 1;
  832.     (void) fputs("---\n", tfp);
  833.     Fprintf(ofp, "%05lx\n", ftell(tfp));    /* start pos of first oracle */
  834.     in_oracle = FALSE;
  835.  
  836.     while (fgets(in_line, sizeof in_line, ifp)) {
  837.         SpinCursor(3);
  838.  
  839.         if (h_filter(in_line)) continue;
  840.         if (!strncmp(in_line, "-----", 5)) {
  841.         if (!in_oracle) continue;
  842.         in_oracle = FALSE;
  843.         oracle_cnt++;
  844.         (void) fputs("---\n", tfp);
  845.         Fprintf(ofp, "%05lx\n", ftell(tfp));
  846.         /* start pos of this oracle */
  847.         } else {
  848.         in_oracle = TRUE;
  849.         (void) fputs(xcrypt(in_line), tfp);
  850.         }
  851.     }
  852.  
  853.     if (in_oracle) {    /* need to terminate last oracle */
  854.         oracle_cnt++;
  855.         (void) fputs("---\n", tfp);
  856.         Fprintf(ofp, "%05lx\n", ftell(tfp));    /* eof position */
  857.     }
  858.  
  859.     /* record the current position */
  860.     txt_offset = ftell(ofp);
  861.     Fclose(ifp);        /* all done with original input file */
  862.  
  863.     /* reprocess the scratch file; 1st format an error msg, just in case */
  864.     Sprintf(in_line, "rewind of \"%s\"", tempfile);
  865.     if (rewind(tfp) != 0)  goto dead_data;
  866.     /* copy all lines of text from the scratch file into the output file */
  867.     while (fgets(in_line, sizeof in_line, tfp))
  868.         (void) fputs(in_line, ofp);
  869.  
  870.     /* finished with scratch file */
  871.     Fclose(tfp);
  872.     Unlink(tempfile);    /* remove it */
  873.  
  874.     /* update the first record of the output file; prepare error msg 1st */
  875.     Sprintf(in_line, "rewind of \"%s\"", filename);
  876.     ok = (rewind(ofp) == 0);
  877.     if (ok) {
  878.         Sprintf(in_line, "header rewrite of \"%s\"", filename);
  879.         ok = (fprintf(ofp, "%s%5d\n", Dont_Edit_Data, (int)oracle_cnt) >=0);
  880.     }
  881.     if (ok) {
  882.         Sprintf(in_line, "data rewrite of \"%s\"", filename);
  883.         for (i = 0; i <= oracle_cnt; i++) {
  884. #ifndef VMS    /* alpha/vms v1.0; this fflush seems to confuse ftell */
  885.         if (!(ok = (fflush(ofp) == 0))) break;
  886. #endif
  887.         if (!(ok = (fpos = ftell(ofp)) >= 0)) break;
  888.         if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0))) break;
  889.         if (!(ok = (fscanf(ofp, "%5lx", &offset) == 1))) break;
  890.         if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0))) break;
  891.         if (!(ok = (fprintf(ofp, "%05lx\n", offset + txt_offset) >= 0)))
  892.             break;
  893.         }
  894.     }
  895.     if (!ok) {
  896. dead_data:  perror(in_line);    /* report the problem */
  897.         /* close and kill the aborted output file, then give up */
  898.         Fclose(ofp);
  899.         Unlink(filename);
  900.         exit(1);
  901.     }
  902.  
  903.     /* all done */
  904.     Fclose(ofp);
  905.  
  906.     return;
  907. }
  908.  
  909.  
  910. static    struct deflist {
  911.  
  912.     const char    *defname;
  913.     boolean    true_or_false;
  914. } deflist[] = {
  915. #ifdef REINCARNATION
  916.           {    "REINCARNATION", TRUE },
  917. #else
  918.           {    "REINCARNATION", FALSE },
  919. #endif
  920. #ifdef MULDGN
  921.           {    "MULDGN", TRUE },
  922. #else
  923.           {    "MULDGN", FALSE },
  924. #endif
  925.           { 0, 0 } };
  926.  
  927. static int
  928. check_control(s)
  929.     char    *s;
  930. {
  931.     int    i;
  932.  
  933.     if(s[0] != '%') return(-1);
  934.  
  935.     for(i = 0; deflist[i].defname; i++)
  936.         if(!strncmp(deflist[i].defname, s+1, sizeof(deflist[i].defname)))
  937.         return(i);
  938.  
  939.     return(-1);
  940. }
  941.  
  942. static char *
  943. without_control(s)
  944.     char *s;
  945. {
  946.     return(s + 1 + strlen(deflist[check_control(in_line)].defname));
  947. }
  948.  
  949. void
  950. do_dungeon()
  951. {
  952.     int rcnt = 0;
  953.  
  954.     Sprintf(filename, DATA_TEMPLATE, DGN_I_FILE);
  955.     if (!(ifp = fopen(filename, RDMODE))) {
  956.         perror(filename);
  957.         exit(1);
  958.     }
  959.     Sprintf(filename, DATA_TEMPLATE, DGN_O_FILE);
  960.     if (!(ofp = fopen(filename, WRMODE))) {
  961.         perror(filename);
  962.         exit(1);
  963.     }
  964.     Fprintf(ofp,Dont_Edit_Data);
  965.  
  966.     while(fgets(in_line,sizeof(in_line),ifp) != NULL) {
  967.  
  968.         SpinCursor(3);
  969.  
  970.         rcnt++;
  971.         if(in_line[0] == '#') continue;    /* discard comments */
  972. recheck:
  973.         if(in_line[0] == '%') {
  974.         int i = check_control(in_line);
  975.         if(i >= 0) {
  976.             if(!deflist[i].true_or_false)  {
  977.             while(fgets(in_line,sizeof(in_line),ifp))
  978.                 if(check_control(in_line) != i) goto recheck;
  979.             } else
  980.             (void) fputs(without_control(in_line),ofp);
  981.         } else {
  982.             Fprintf(stderr, "Unknown control option '%s' in file %s at line %d.\n",
  983.                 in_line, DGN_I_FILE, rcnt);
  984.             exit(1);
  985.         }
  986.         } else
  987.         (void) fputs(in_line,ofp);
  988.     }
  989.     Fclose(ifp);
  990.     Fclose(ofp);
  991.  
  992.     return;
  993. }
  994.  
  995. static boolean
  996. ranged_attk(ptr)    /* returns TRUE if monster can attack at range */
  997.     register struct permonst *ptr;
  998. {
  999.     register int    i, j;
  1000.     register int atk_mask = (1<<AT_BREA) | (1<<AT_SPIT) | (1<<AT_GAZE);
  1001.  
  1002.     for(i = 0; i < NATTK; i++) {
  1003.         if((j=ptr->mattk[i].aatyp) >= AT_WEAP || (atk_mask & (1<<j)))
  1004.         return TRUE;
  1005.     }
  1006.  
  1007.     return(FALSE);
  1008. }
  1009.  
  1010. /* This routine is designed to return an integer value which represents
  1011.  * an approximation of monster strength.  It uses a similar method of
  1012.  * determination as "experience()" to arrive at the strength.
  1013.  */
  1014. static int
  1015. mstrength(ptr)
  1016. struct permonst *ptr;
  1017. {
  1018.     int    i, tmp2, n, tmp = ptr->mlevel;
  1019.  
  1020.     if(tmp > 49)        /* special fixed hp monster */
  1021.         tmp = 2*(tmp - 6) / 4;
  1022.  
  1023. /*    For creation in groups */
  1024.     n = (!!(ptr->geno & G_SGROUP));
  1025.     n += (!!(ptr->geno & G_LGROUP)) << 1;
  1026.  
  1027. /*    For ranged attacks */
  1028.     if (ranged_attk(ptr)) n++;
  1029.  
  1030. /*    For higher ac values */
  1031.     n += (ptr->ac < 4);
  1032.     n += (ptr->ac < 0);
  1033.  
  1034. /*    For very fast monsters */
  1035.     n += (ptr->mmove >= 18);
  1036.  
  1037. /*    For each attack and "special" attack */
  1038.     for(i = 0; i < NATTK; i++) {
  1039.  
  1040.         tmp2 = ptr->mattk[i].aatyp;
  1041.         n += (tmp2 > 0);
  1042.         n += (tmp2 == AT_MAGC);
  1043.         n += (tmp2 == AT_WEAP && (ptr->mflags2 & M2_STRONG));
  1044.     }
  1045.  
  1046. /*    For each "special" damage type */
  1047.     for(i = 0; i < NATTK; i++) {
  1048.  
  1049.         tmp2 = ptr->mattk[i].adtyp;
  1050.         if((tmp2 == AD_DRLI) || (tmp2 == AD_STON) || (tmp2 == AD_DRST)
  1051.             || (tmp2 == AD_DRDX) || (tmp2 == AD_DRCO)
  1052. #ifdef POLYSELF
  1053.                     || (tmp2 == AD_WERE)
  1054. #endif
  1055.                                 ) n += 2;
  1056.         else if (strcmp(ptr->mname, "grid bug")) n += (tmp2 != AD_PHYS);
  1057.         n += ((int) (ptr->mattk[i].damd * ptr->mattk[i].damn) > 23);
  1058.     }
  1059.  
  1060. /*    Leprechauns are special cases.  They have many hit dice so they
  1061.     can hit and are hard to kill, but they don't really do much damage. */
  1062.     if (!strcmp(ptr->mname, "leprechaun")) n -= 2;
  1063.  
  1064. /*    Finally, adjust the monster level  0 <= n <= 24 (approx.) */
  1065.     if(n == 0) tmp--;
  1066.     else if(n >= 6) tmp += ( n / 2 );
  1067.     else tmp += ( n / 3 + 1);
  1068.  
  1069.     return((tmp >= 0) ? tmp : 0);
  1070. }
  1071.  
  1072. void
  1073. do_monstr()
  1074. {
  1075.     register struct permonst *ptr;
  1076.     register int i, j;
  1077.  
  1078.     /*
  1079.      * create the source file, "monstr.c"
  1080.      */
  1081.     Sprintf(filename, SOURCE_TEMPLATE, MON_STR_C);
  1082.     if (!(ofp = fopen(filename, WRMODE))) {
  1083.     perror(filename);
  1084.     exit(1);
  1085.     }
  1086.     Fprintf(ofp,Dont_Edit_Code);
  1087.     Fprintf(ofp,"#include \"config.h\"\n");
  1088.     Fprintf(ofp,"\nint monstr[] = {\n");
  1089.     for (ptr = &mons[0], j = 0; ptr->mlet; ptr++) {
  1090.  
  1091.     SpinCursor(3);
  1092.  
  1093.     i = mstrength(ptr);
  1094.     Fprintf(ofp,"%2d,%c", i, (++j & 15) ? ' ' : '\n');
  1095.     }
  1096.     /* might want to insert a final 0 entry here instead of just newline */
  1097.     Fprintf(ofp,"%s};\n", (j & 15) ? "\n" : "");
  1098.  
  1099.     Fprintf(ofp,"\nvoid NDECL(monstr_init);\n");
  1100.     Fprintf(ofp,"\nvoid\n");
  1101.     Fprintf(ofp,"monstr_init()\n");
  1102.     Fprintf(ofp,"{\n");
  1103.     Fprintf(ofp,"    return;\n");
  1104.     Fprintf(ofp,"}\n");
  1105.     Fprintf(ofp,"\n/*monstr.c*/\n");
  1106.  
  1107.     Fclose(ofp);
  1108.     return;
  1109. }
  1110.  
  1111. void
  1112. do_permonst()
  1113. {
  1114.     int    i;
  1115.     char    *c, *nam;
  1116.  
  1117.     Sprintf(filename, INCLUDE_TEMPLATE, MONST_FILE);
  1118.     if (!(ofp = fopen(filename, WRMODE))) {
  1119.         perror(filename);
  1120.         exit(1);
  1121.     }
  1122.     Fprintf(ofp,"/*\tSCCS Id: @(#)pm.h\t3.1\t92/01/04 */\n\n");
  1123.     Fprintf(ofp,Dont_Edit_Code);
  1124.     Fprintf(ofp,"#ifndef PM_H\n#define PM_H\n");
  1125.  
  1126.     for(i = 0; mons[i].mlet; i++) {
  1127.  
  1128.         SpinCursor(3);
  1129.  
  1130.         Fprintf(ofp,"\n#define\tPM_");
  1131.         if (mons[i].mlet == S_HUMAN &&
  1132.                 !strncmp(mons[i].mname, "were", 4))
  1133.             Fprintf(ofp, "HUMAN_");
  1134.         for (nam = c = tmpdup(mons[i].mname); *c; c++)
  1135.             if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A');
  1136.             else if (*c < 'A' || *c > 'Z') *c = '_';
  1137.         Fprintf(ofp,"%s\t%d", nam, i);
  1138.     }
  1139.     Fprintf(ofp,"\n\n#define\tNUMMONS\t%d\n", i);
  1140.     Fprintf(ofp,"\n#endif /* PM_H */\n");
  1141.     Fclose(ofp);
  1142.     return;
  1143. }
  1144.  
  1145. #ifdef MULDGN
  1146. /*    Start of Quest text file processing. */
  1147. #include "qtext.h"
  1148.  
  1149. static struct qthdr    qt_hdr;
  1150. static struct msghdr    msg_hdr[N_HDR];
  1151. static struct qtmsg    *curr_msg;
  1152.  
  1153. static int    qt_line;
  1154.  
  1155. static boolean    in_msg;
  1156. #define    NO_MSG    1    /* strlen of a null line returned by fgets() */
  1157.  
  1158. static boolean
  1159. qt_comment(s)
  1160.  
  1161.     char *s;
  1162. {
  1163.     if(s[0] == '#') return(TRUE);
  1164.     return(!in_msg  && strlen(s) == NO_MSG);
  1165. }
  1166.  
  1167. static boolean
  1168. qt_control(s)
  1169.  
  1170.     char *s;
  1171. {
  1172.     return(s[0] == '%' && (s[1] == 'C' || s[1] == 'E'));
  1173. }
  1174.  
  1175. static int
  1176. get_hdr(c)
  1177.  
  1178.     char c;
  1179. {
  1180.     int    i;
  1181.  
  1182.     for(i = 0; i < qt_hdr.n_hdr; i++)
  1183.         if(c == qt_hdr.id[i]) return (++i);
  1184.  
  1185.     return(0);
  1186. }
  1187.  
  1188. static boolean
  1189. known_id(c)
  1190.  
  1191.     char c;
  1192. {
  1193.     return(get_hdr(c) > 0);
  1194. }
  1195.  
  1196. static boolean
  1197. new_id(c)
  1198.  
  1199.     char c;
  1200. {
  1201.     if(qt_hdr.n_hdr >= N_HDR) {
  1202.  
  1203.         Fprintf(stderr, OUT_OF_HEADERS, qt_line);
  1204.         return(FALSE);
  1205.     }
  1206.  
  1207.     qt_hdr.id[qt_hdr.n_hdr] = c;
  1208.     msg_hdr[qt_hdr.n_hdr].n_msg = 0;
  1209.     qt_hdr.offset[qt_hdr.n_hdr++] = 0L;
  1210.     return(TRUE);
  1211. }
  1212.  
  1213. static boolean
  1214. known_msg(c, s)
  1215.  
  1216.     char c, *s;
  1217. {
  1218.     int i = get_hdr(c) - 1,
  1219.         j, n = atoi(s);
  1220.  
  1221.     for(j = 0; j < msg_hdr[i].n_msg; j++)
  1222.         if(msg_hdr[i].qt_msg[j].msgnum == n) return(TRUE);
  1223.  
  1224.     return(FALSE);
  1225. }
  1226.  
  1227.  
  1228. static void
  1229. new_msg(s)
  1230. char *s;
  1231. {
  1232.     struct    qtmsg    *qt_msg;
  1233.     int    i = get_hdr(s[4]) - 1;
  1234.  
  1235.     if(msg_hdr[i].n_msg >= N_MSG) {
  1236.         Fprintf(stderr, OUT_OF_MESSAGES, qt_line);
  1237.     } else {
  1238.         qt_msg = &(msg_hdr[i].qt_msg[msg_hdr[i].n_msg++]);
  1239.         qt_msg->msgnum = atoi(s+5);
  1240.         qt_msg->delivery = s[2];
  1241.         qt_msg->offset = qt_msg->size = 0L;
  1242.  
  1243.         curr_msg = qt_msg;
  1244.     }
  1245. }
  1246.  
  1247. static void
  1248. do_qt_control(s)
  1249.  
  1250.     char *s;
  1251. {
  1252.     switch(s[1]) {
  1253.  
  1254.         case 'C':    if(in_msg) {
  1255.                 Fprintf(stderr, CREC_IN_MSG, qt_line);
  1256.                 break;
  1257.             } else {
  1258.                 in_msg = TRUE;
  1259.                 if(!known_id(s[4]))
  1260.                 if(!new_id(s[4])) break;
  1261.                 if(known_msg(s[4],&s[5]))
  1262.                 Fprintf(stderr, DUP_MSG, qt_line);
  1263.                 else new_msg(s);
  1264.             }
  1265.             break;
  1266.  
  1267.         case 'E':    if(!in_msg) {
  1268.                 Fprintf(stderr, END_NOT_IN_MSG, qt_line);
  1269.                 break;
  1270.             } else in_msg = FALSE;
  1271.             break;
  1272.  
  1273.         default:    Fprintf(stderr, UNREC_CREC, qt_line);
  1274.             break;
  1275.     }
  1276. }
  1277.  
  1278. static void
  1279. do_qt_text(s)
  1280.  
  1281.     char *s;
  1282. {
  1283.     curr_msg->size += strlen(s);
  1284. }
  1285.  
  1286. static void
  1287. adjust_qt_hdrs() {
  1288.  
  1289.     int    i, j;
  1290.     long    count = 0L,
  1291.         hdr_offset = sizeof(int) +
  1292.                  (sizeof(char) + sizeof(long)) * qt_hdr.n_hdr;
  1293.  
  1294.     for(i = 0; i < qt_hdr.n_hdr; i++) {
  1295.  
  1296.         qt_hdr.offset[i] = hdr_offset;
  1297.         hdr_offset += sizeof(int) + sizeof(struct qtmsg) * msg_hdr[i].n_msg;
  1298.     }
  1299.  
  1300.     for(i = 0; i < qt_hdr.n_hdr; i++)
  1301.         for(j = 0; j < msg_hdr[i].n_msg; j++) {
  1302.  
  1303.         msg_hdr[i].qt_msg[j].offset = hdr_offset + count;
  1304.         count += msg_hdr[i].qt_msg[j].size;
  1305.         }
  1306. }
  1307.  
  1308. static void
  1309. put_qt_hdrs() {
  1310.  
  1311.     int    i;
  1312.  
  1313.     /*
  1314.      *    The main header record.
  1315.      */
  1316. #ifdef DEBUG
  1317.     Fprintf(stderr, "%ld: header info.\n", ftell(ofp));
  1318. #endif
  1319.     (void) fwrite(&(qt_hdr.n_hdr), sizeof(int), 1, ofp);
  1320.     (void) fwrite(&(qt_hdr.id[0]), sizeof(char), qt_hdr.n_hdr, ofp);
  1321.     (void) fwrite(&(qt_hdr.offset[0]), sizeof(long), qt_hdr.n_hdr, ofp);
  1322. #ifdef DEBUG
  1323.     for(i = 0; i < qt_hdr.n_hdr; i++)
  1324.         Fprintf(stderr, "%c @ %ld, ", qt_hdr.id[i], qt_hdr.offset[i]);
  1325.  
  1326.     Fprintf(stderr, "\n");
  1327. #endif
  1328.  
  1329.     /*
  1330.      *    The individual class headers.
  1331.      */
  1332.     for(i = 0; i < qt_hdr.n_hdr; i++) {
  1333.  
  1334. #ifdef DEBUG
  1335.         Fprintf(stderr, "%ld: %c header info.\n", ftell(ofp),
  1336.             qt_hdr.id[i]);
  1337. #endif
  1338.         (void) fwrite(&(msg_hdr[i].n_msg), sizeof(int), 1, ofp);
  1339.         (void) fwrite(&(msg_hdr[i].qt_msg[0]), sizeof(struct qtmsg),
  1340.            msg_hdr[i].n_msg, ofp);
  1341. #ifdef DEBUG
  1342.         { int j;
  1343.           for(j = 0; j < msg_hdr[i].n_msg; j++)
  1344.         Fprintf(stderr, "msg %d @ %ld (%ld)\n",
  1345.             msg_hdr[i].qt_msg[j].msgnum,
  1346.             msg_hdr[i].qt_msg[j].offset,
  1347.             msg_hdr[i].qt_msg[j].size);
  1348.         }
  1349. #endif
  1350.     }
  1351. }
  1352.  
  1353. void
  1354. do_questtxt()
  1355. {
  1356.     Sprintf(filename, DATA_TEMPLATE, QTXT_I_FILE);
  1357.     if(!(ifp = fopen(filename, RDMODE))) {
  1358.         perror(filename);
  1359.         exit(1);
  1360.     }
  1361.  
  1362.     Sprintf(filename, DATA_TEMPLATE, QTXT_O_FILE);
  1363.     if(!(ofp = fopen(filename, WRBMODE))) {
  1364.         perror(filename);
  1365.         Fclose(ifp);
  1366.         exit(1);
  1367.     }
  1368.  
  1369.     qt_hdr.n_hdr = 0;
  1370.     qt_line = 0;
  1371.     in_msg = FALSE;
  1372.  
  1373.     while(fgets(in_line, 80, ifp) != NULL) {
  1374.  
  1375.         SpinCursor (3);
  1376.  
  1377.         qt_line++;
  1378.         if(qt_control(in_line)) do_qt_control(in_line);
  1379.         else if(qt_comment(in_line)) continue;
  1380.         else            do_qt_text(in_line);
  1381.     }
  1382.  
  1383.     (void) rewind(ifp);
  1384.     in_msg = FALSE;
  1385.     adjust_qt_hdrs(); put_qt_hdrs();
  1386.     while(fgets(in_line, 80, ifp) != NULL) {
  1387.  
  1388.         if(qt_control(in_line)) {
  1389.             in_msg = (in_line[1] == 'C');
  1390.             continue;
  1391.         } else if(qt_comment(in_line)) continue;
  1392. #ifdef DEBUG
  1393.         Fprintf(stderr, "%ld: %s", ftell(stdout), in_line);
  1394. #endif
  1395.         (void) fputs(xcrypt(in_line), ofp);
  1396.     }
  1397.     Fclose(ifp);
  1398.     Fclose(ofp);
  1399.     return;
  1400. }
  1401. #else    /* not MULDGN */
  1402.  
  1403. void
  1404. do_questtxt()
  1405. {
  1406.     Fprintf(stderr, "makedefs: `-q' option ignored.\n");
  1407.     /* create an empty file to satisfy `make' */
  1408.     Sprintf(filename, DATA_TEMPLATE, QTXT_O_FILE);
  1409.     ofp = fopen(filename, WRBMODE);
  1410.     Fclose(ofp);
  1411.     return;
  1412. }
  1413.  
  1414. #endif /* MULDGN */
  1415.  
  1416. static    char    temp[32];
  1417.  
  1418. char *
  1419. limit(name,pref)    /* limit a name to 30 characters length */
  1420. char    *name;
  1421. int    pref;
  1422. {
  1423.     (void) strncpy(temp, name, pref ? 26 : 30);
  1424.     temp[pref ? 26 : 30] = 0;
  1425.     return temp;
  1426. }
  1427.  
  1428. void
  1429. do_objs()
  1430. {
  1431.     int i, sum = 0;
  1432.     char *c, *objnam;
  1433.     int nspell = 0;
  1434.     int prefix = 0;
  1435.     char class = '\0';
  1436.     boolean    sumerr = FALSE;
  1437.  
  1438.     Sprintf(filename, INCLUDE_TEMPLATE, ONAME_FILE);
  1439.     if (!(ofp = fopen(filename, WRMODE))) {
  1440.         perror(filename);
  1441.         exit(1);
  1442.     }
  1443.     Fprintf(ofp,"/*\tSCCS Id: @(#)onames.h\t3.1\t92/11/01 */\n\n");
  1444.     Fprintf(ofp,Dont_Edit_Code);
  1445.     Fprintf(ofp,"#ifndef ONAMES_H\n#define ONAMES_H\n\n");
  1446.  
  1447.     for(i = 0; !i || objects[i].oc_class != ILLOBJ_CLASS; i++) {
  1448.         SpinCursor(3);
  1449.  
  1450.         objects[i].oc_name_idx = objects[i].oc_descr_idx = i;    /* init */
  1451.         if (!(objnam = tmpdup(OBJ_NAME(objects[i])))) continue;
  1452.  
  1453.         /* make sure probabilities add up to 1000 */
  1454.         if(objects[i].oc_class != class) {
  1455.             if (sum && sum != 1000) {
  1456.                 Fprintf(stderr, "prob error for class %d (%d%%)",
  1457.                     class, sum);
  1458.                 (void) fflush(stderr);
  1459.                 sumerr = TRUE;
  1460.             }
  1461.             class = objects[i].oc_class;
  1462.             sum = 0;
  1463.         }
  1464.  
  1465.         for (c = objnam; *c; c++)
  1466.             if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A');
  1467.             else if (*c < 'A' || *c > 'Z') *c = '_';
  1468.  
  1469.         switch (class) {
  1470.             case WAND_CLASS:
  1471.             Fprintf(ofp,"#define\tWAN_"); prefix = 1; break;
  1472.             case RING_CLASS:
  1473.             Fprintf(ofp,"#define\tRIN_"); prefix = 1; break;
  1474.             case POTION_CLASS:
  1475.             Fprintf(ofp,"#define\tPOT_"); prefix = 1; break;
  1476.             case SPBOOK_CLASS:
  1477.             Fprintf(ofp,"#define\tSPE_"); prefix = 1; nspell++; break;
  1478.             case SCROLL_CLASS:
  1479.             Fprintf(ofp,"#define\tSCR_"); prefix = 1; break;
  1480.             case AMULET_CLASS:
  1481.             /* avoid trouble with stupid C preprocessors */
  1482.             Fprintf(ofp,"#define\t");
  1483.             if(objects[i].oc_material == PLASTIC) {
  1484.                 Fprintf(ofp,"FAKE_AMULET_OF_YENDOR\t%d\n", i);
  1485.                 prefix = -1;
  1486.                 break;
  1487.             }
  1488.             break;
  1489.             case GEM_CLASS:
  1490.             /* avoid trouble with stupid C preprocessors */
  1491.             if(objects[i].oc_material == GLASS) {
  1492.                 Fprintf(ofp,"/* #define\t%s\t%d */\n",
  1493.                             objnam, i);
  1494.                 prefix = -1;
  1495.                 break;
  1496.             }
  1497.             default:
  1498.             Fprintf(ofp,"#define\t");
  1499.         }
  1500.         if (prefix >= 0)
  1501.             Fprintf(ofp,"%s\t%d\n", limit(objnam, prefix), i);
  1502.         prefix = 0;
  1503.  
  1504.         sum += objects[i].oc_prob;
  1505.     }
  1506.  
  1507.     /* check last set of probabilities */
  1508.     if (sum && sum != 1000) {
  1509.         Fprintf(stderr, "prob error for class %d (%d%%)", class, sum);
  1510.         (void) fflush(stderr);
  1511.         sumerr = TRUE;
  1512.     }
  1513.  
  1514.     Fprintf(ofp,"#define\tLAST_GEM\t(JADE)\n");
  1515.     Fprintf(ofp,"#define\tMAXSPELL\t%d\n", nspell+1);
  1516.     Fprintf(ofp,"#define\tNROFOBJECTS\t%d\n", i-1);
  1517.  
  1518.     Fprintf(ofp, "\n/* Artifacts (unique objects) */\n\n");
  1519.  
  1520.     for (i = 1; artifact_names[i]; i++) {
  1521.         SpinCursor(3);
  1522.  
  1523.         for (c = objnam = tmpdup(artifact_names[i]); *c; c++)
  1524.             if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A');
  1525.             else if (*c < 'A' || *c > 'Z') *c = '_';
  1526.  
  1527.         if (!strncmp(objnam, "THE_", 4))
  1528.             objnam += 4;
  1529. #ifdef TOURIST
  1530.         /* fudge _platinum_ YENDORIAN EXPRESS CARD */
  1531.         if (!strncmp(objnam, "PLATINUM_", 9))
  1532.             objnam += 9;
  1533. #endif
  1534.         Fprintf(ofp,"#define\tART_%s\t%d\n", limit(objnam, 1), i);
  1535.     }
  1536.  
  1537.     Fprintf(ofp, "#define\tNROFARTIFACTS\t%d\n", i-1);
  1538.     Fprintf(ofp,"\n#endif /* ONAMES_H */\n");
  1539.     Fclose(ofp);
  1540.     if (sumerr) exit(1);
  1541.     return;
  1542. }
  1543.  
  1544. char *
  1545. tmpdup(str)
  1546. const char *str;
  1547. {
  1548.     static char buf[128];
  1549.  
  1550.     if (!str) return (char *)0;
  1551.     (void)strncpy(buf, str, 127);
  1552.     return buf;
  1553. }
  1554.  
  1555.  
  1556. /*
  1557.  * macros used to control vision algorithms:
  1558.  *      VISION_TABLES => generate tables
  1559.  *      BRACES        => table elements should be enclosed in "{ }"
  1560.  */
  1561.  
  1562. void
  1563. do_vision()
  1564. {
  1565. #ifdef VISION_TABLES
  1566.     int i, j;
  1567.  
  1568.     /* Everything is clear.  xclear may be malloc'ed.
  1569.      * Block the upper left corner (BLOCK_HEIGHTxBLOCK_WIDTH)
  1570.      */
  1571.     for (i = 0; i < MAX_ROW; i++)
  1572.     for (j = 0; j < MAX_COL; j++)
  1573.         if (i < BLOCK_HEIGHT && j < BLOCK_WIDTH)
  1574.         xclear[i][j] = '\000';
  1575.         else
  1576.         xclear[i][j] = '\001';
  1577. #endif /* VISION_TABLES */
  1578.  
  1579.     SpinCursor(3);
  1580.  
  1581.     /*
  1582.      * create the include file, "vis_tab.h"
  1583.      */
  1584.     Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H);
  1585.     if (!(ofp = fopen(filename, WRMODE))) {
  1586.     perror(filename);
  1587.     exit(1);
  1588.     }
  1589.     Fprintf(ofp,Dont_Edit_Code);
  1590.     Fprintf(ofp,"#ifdef VISION_TABLES\n");
  1591. #ifdef VISION_TABLES
  1592.     H_close_gen();
  1593.     H_far_gen();
  1594. #endif /* VISION_TABLES */
  1595.     Fprintf(ofp,"\n#endif /* VISION_TABLES */\n");
  1596.     Fclose(ofp);
  1597.  
  1598.     SpinCursor(3);
  1599.  
  1600.     /*
  1601.      * create the source file, "vis_tab.c"
  1602.      */
  1603.     Sprintf(filename, SOURCE_TEMPLATE, VIS_TAB_C);
  1604.     if (!(ofp = fopen(filename, WRMODE))) {
  1605.     perror(filename);
  1606.     Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H);
  1607.     Unlink(filename);
  1608.     exit(1);
  1609.     }
  1610.     Fprintf(ofp,Dont_Edit_Code);
  1611.     Fprintf(ofp,"#include \"config.h\"\n");
  1612.     Fprintf(ofp,"#ifdef VISION_TABLES\n");
  1613.     Fprintf(ofp,"#include \"vis_tab.h\"\n");
  1614.  
  1615.     SpinCursor(3);
  1616.  
  1617. #ifdef VISION_TABLES
  1618.     C_close_gen();
  1619.     C_far_gen();
  1620.     Fprintf(ofp,"\nvoid vis_tab_init() { return; }\n");
  1621. #endif /* VISION_TABLES */
  1622.  
  1623.     SpinCursor(3);
  1624.  
  1625.     Fprintf(ofp,"\n#endif /* VISION_TABLES */\n");
  1626.     Fprintf(ofp,"\n/*vis_tab.c*/\n");
  1627.  
  1628.     Fclose(ofp);
  1629.     return;
  1630. }
  1631.  
  1632. #ifdef VISION_TABLES
  1633.  
  1634. /*--------------  vision tables  --------------*\
  1635.  *
  1636.  *  Generate the close and far tables.  This is done by setting up a
  1637.  *  fake dungeon and moving our source to different positions relative
  1638.  *  to a block and finding the first/last visible position.  The fake
  1639.  *  dungeon is all clear execpt for the upper left corner (BLOCK_HEIGHT
  1640.  *  by BLOCK_WIDTH) is blocked.  Then we move the source around relative
  1641.  *  to the corner of the block.  For each new position of the source
  1642.  *  we check positions on rows "kittycorner" from the source.  We check
  1643.  *  positions until they are either in sight or out of sight (depends on
  1644.  *  which table we are generating).  The picture below shows the setup
  1645.  *  for the generation of the close table.  The generation of the far
  1646.  *  table would switch the quadrants of the '@' and the "Check rows
  1647.  *  here".
  1648.  *
  1649.  *
  1650.  *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1651.  *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1652.  *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,, Check rows here ,,,,,,,,,,,,
  1653.  *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1654.  *  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXB,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1655.  *  ...............................
  1656.  *  ...............................
  1657.  *  .........@.....................
  1658.  *  ...............................
  1659.  *
  1660.  *      Table generation figure (close_table).  The 'X's are blocked points.
  1661.  *      The 'B' is a special blocked point.  The '@' is the source.  The ','s
  1662.  *      are the target area.  The '.' are just open areas.
  1663.  *
  1664.  *
  1665.  *  Example usage of close_table[][][].
  1666.  *
  1667.  *  The table is as follows:
  1668.  *
  1669.  *      dy = |row of '@' - row of 'B'|  - 1
  1670.  *      dx = |col of '@' - col of 'B'|
  1671.  *
  1672.  *  The first indices are the deltas from the source '@' and the block 'B'.
  1673.  *  You must check for the value inside the abs value bars being zero.  If
  1674.  *  so then the block is on the same row and you don't need to do a table
  1675.  *  lookup.  The last value:
  1676.  *
  1677.  *      dcy = |row of block - row to be checked|
  1678.  *
  1679.  *  Is the value of the first visible spot on the check row from the
  1680.  *  block column.  So
  1681.  *
  1682.  *  first visible col = close_table[dy][dx][dcy] + col of 'B'
  1683.  *
  1684. \*--------------  vision tables  --------------*/
  1685.  
  1686. static void
  1687. H_close_gen()
  1688. {
  1689.     Fprintf(ofp,"\n/* Close */\n");
  1690.     Fprintf(ofp,"#define CLOSE_MAX_SB_DY %2d\t/* |src row - block row| - 1\t*/\n",
  1691.         TEST_HEIGHT-1);
  1692.     Fprintf(ofp,"#define CLOSE_MAX_SB_DX %2d\t/* |src col - block col|\t*/\n",
  1693.         TEST_WIDTH);
  1694.     Fprintf(ofp,"#define CLOSE_MAX_BC_DY %2d\t/* |block row - check row|\t*/\n",
  1695.         TEST_HEIGHT);
  1696.     Fprintf(ofp,"typedef struct {\n");
  1697.     Fprintf(ofp,"    unsigned char close[CLOSE_MAX_SB_DX][CLOSE_MAX_BC_DY];\n");
  1698.     Fprintf(ofp,"} close2d;\n");
  1699.     Fprintf(ofp,"extern close2d close_table[CLOSE_MAX_SB_DY];\n");
  1700.     return;
  1701. }
  1702.  
  1703. static void
  1704. H_far_gen()
  1705. {
  1706.     Fprintf(ofp,"\n/* Far */\n");
  1707.     Fprintf(ofp,"#define FAR_MAX_SB_DY %2d\t/* |src row - block row|\t*/\n",
  1708.         TEST_HEIGHT);
  1709.     Fprintf(ofp,"#define FAR_MAX_SB_DX %2d\t/* |src col - block col| - 1\t*/\n",
  1710.         TEST_WIDTH-1);
  1711.     Fprintf(ofp,"#define FAR_MAX_BC_DY %2d\t/* |block row - check row| - 1\t*/\n",
  1712.         TEST_HEIGHT-1);
  1713.     Fprintf(ofp,"typedef struct {\n");
  1714.     Fprintf(ofp,"    unsigned char far_q[FAR_MAX_SB_DX][FAR_MAX_BC_DY];\n");
  1715.     Fprintf(ofp,"} far2d;\n");
  1716.     Fprintf(ofp,"extern far2d far_table[FAR_MAX_SB_DY];\n");
  1717.     return;
  1718. }
  1719.  
  1720. # ifdef BRACES
  1721. #  define L_BRACE "{"
  1722. #  define R_BRACE "},"
  1723. # else
  1724. #  define L_BRACE ""
  1725. #  define R_BRACE ""
  1726. # endif /* BRACES */
  1727.  
  1728. static void
  1729. C_close_gen()
  1730. {
  1731.     int i,dx,dy;
  1732.     int src_row, src_col;    /* source */
  1733.     int block_row, block_col;    /* block */
  1734.     int this_row;
  1735.     int no_more;
  1736.  
  1737.     block_row = BLOCK_HEIGHT-1;
  1738.     block_col = BLOCK_WIDTH-1;
  1739.  
  1740.     Fprintf(ofp,"\n#ifndef FAR_TABLE_ONLY\n");
  1741.     Fprintf(ofp,"\nclose2d close_table[CLOSE_MAX_SB_DY] = {\n");
  1742. #ifndef no_vision_progress
  1743.     Fprintf(stderr,"\nclose:");
  1744. #endif
  1745.  
  1746.     for (dy = 1; dy < TEST_HEIGHT; dy++) {
  1747.     src_row = block_row + dy;
  1748.     Fprintf(ofp,"/* DY = %2d (- 1)*/\n  {\n",dy);
  1749. #ifndef no_vision_progress
  1750.     Fprintf(stderr," %2d",dy),  (void)fflush(stderr);
  1751. #endif
  1752.     for (dx = 0; dx < TEST_WIDTH; dx++) {
  1753.         src_col = block_col - dx;
  1754.         Fprintf(ofp,"  /*%2d*/  %s",dx, L_BRACE);
  1755.  
  1756.         no_more = 0;
  1757.         for (this_row = 0; this_row < TEST_HEIGHT; this_row++) {
  1758.         if (no_more) {
  1759.             Fprintf(ofp,CLOSE_OFF_TABLE_STRING);
  1760.             continue;
  1761.         }
  1762.  
  1763.         SpinCursor(3);
  1764.  
  1765.         /* Find the first column that we can see. */
  1766.         for (i = block_col+1; i < MAX_COL; i++) {
  1767.  
  1768.             if (clear_path(src_row,src_col,block_row-this_row,i))
  1769.             break;
  1770.         }
  1771.  
  1772.         if (i == MAX_COL) no_more = 1;
  1773.         Fprintf(ofp,"%2d,",i-block_col);
  1774.         }
  1775.         Fprintf(ofp,"%s\n", R_BRACE);
  1776.     }
  1777.     Fprintf(ofp,"  },\n");
  1778.     }
  1779.  
  1780.     Fprintf(ofp,"}; /* close_table[] */\n");        /* closing brace for table */
  1781.     Fprintf(ofp,"#endif /* !FAR_TABLE_ONLY */\n");
  1782. #ifndef no_vision_progress
  1783.     Fprintf(stderr,"\n");
  1784. #endif
  1785.     return;
  1786. }
  1787.  
  1788. static void
  1789. C_far_gen()
  1790. {
  1791.     int i,dx,dy;
  1792.     int src_row, src_col;    /* source */
  1793.     int block_row, block_col;    /* block */
  1794.     int this_row;
  1795.  
  1796.     block_row = BLOCK_HEIGHT-1;
  1797.     block_col = BLOCK_WIDTH-1;
  1798.  
  1799.     Fprintf(ofp,"\n#ifndef CLOSE_TABLE_ONLY\n");
  1800.     Fprintf(ofp,"\nfar2d far_table[FAR_MAX_SB_DY] = {\n");
  1801. #ifndef no_vision_progress
  1802.     Fprintf(stderr,"\n_far_:");
  1803. #endif
  1804.  
  1805.     for (dy = 0; dy < TEST_HEIGHT; dy++) {
  1806.     src_row = block_row - dy;
  1807.     Fprintf(ofp,"/* DY = %2d */\n  {\n",dy);
  1808. #ifndef no_vision_progress
  1809.     Fprintf(stderr," %2d",dy),  (void)fflush(stderr);
  1810. #endif
  1811.     for (dx = 1; dx < TEST_WIDTH; dx++) {
  1812.         src_col = block_col + dx;
  1813.         Fprintf(ofp,"  /*%2d(-1)*/ %s",dx, L_BRACE);
  1814.  
  1815.         for (this_row = block_row+1; this_row < block_row+TEST_HEIGHT;
  1816.                                 this_row++) {
  1817.         /* Find first col that we can see. */
  1818.         for (i = 0; i <= block_col; i++) {
  1819.  
  1820.             SpinCursor(3);
  1821.  
  1822.             if (clear_path(src_row,src_col,this_row,i)) break;
  1823.         }
  1824.  
  1825.         if (block_col-i < 0)
  1826.             Fprintf(ofp,FAR_OFF_TABLE_STRING);
  1827.         else
  1828.             Fprintf(ofp,"%2d,",block_col-i);
  1829.         }
  1830.         Fprintf(ofp,"%s\n", R_BRACE);
  1831.     }
  1832.     Fprintf(ofp,"  },\n");
  1833.     }
  1834.  
  1835.     Fprintf(ofp,"}; /* far_table[] */\n");    /* closing brace for table */
  1836.     Fprintf(ofp,"#endif /* !CLOSE_TABLE_ONLY */\n");
  1837. #ifndef no_vision_progress
  1838.     Fprintf(stderr,"\n");
  1839. #endif
  1840.     return;
  1841. }
  1842.  
  1843. /*
  1844.  *  "Draw" a line from the hero to the given location.  Stop of we hit a
  1845.  *  wall.
  1846.  *
  1847.  *  Generalized integer Bresenham's algorithm (fast line drawing) for
  1848.  *  all quadrants.  From _Procedural Elements for Computer Graphics_, by
  1849.  *  David F. Rogers.  McGraw-Hill, 1985.
  1850.  *
  1851.  *  I have tried a little bit of optimization by pulling compares out of
  1852.  *  the inner loops.
  1853.  *
  1854.  *  NOTE:  This had better *not* be called from a position on the
  1855.  *  same row as the hero.
  1856.  */
  1857. static int
  1858. clear_path(you_row,you_col,y2,x2)
  1859.     int you_row, you_col, y2, x2;
  1860. {
  1861.     int dx, dy, s1, s2;
  1862.     register int i, error, x, y, dxs, dys;
  1863.  
  1864.     x  = you_col;        y  = you_row;
  1865.     dx = abs(x2-you_col);    dy = abs(y2-you_row);
  1866.     s1 = sign(x2-you_col);    s2 = sign(y2-you_row);
  1867.  
  1868.     if (s1 == 0) {    /* same column */
  1869.     if (s2 == 1) {    /* below (larger y2 value) */
  1870.         for (i = you_row+1; i < y2; i++)
  1871.         if (!xclear[i][you_col]) return 0;
  1872.     } else {    /* above (smaller y2 value) */
  1873.         for (i = y2+1; i < you_row; i++)
  1874.         if (!xclear[i][you_col]) return 0;
  1875.     }
  1876.     return 1;
  1877.     }
  1878.  
  1879.     /*
  1880.      *  Lines at 0 and 90 degrees have been weeded out.
  1881.      */
  1882.     if (dy > dx) {
  1883.     error = dx; dx = dy; dy = error;    /* swap the values */
  1884.     dxs = dx << 1;        /* save the shifted values */
  1885.     dys = dy << 1;
  1886.     error = dys - dx;    /* NOTE: error is used as a temporary above */
  1887.  
  1888.     for (i = 0; i < dx; i++) {
  1889.         if (!xclear[y][x]) return 0;    /* plot point */
  1890.  
  1891.         while (error >= 0) {
  1892.         x += s1;
  1893.         error -= dxs;
  1894.         }
  1895.         y += s2;
  1896.         error += dys;
  1897.     }
  1898.     } else {
  1899.     dxs = dx << 1;        /* save the shifted values */
  1900.     dys = dy << 1;
  1901.     error = dys - dx;
  1902.  
  1903.     for (i = 0; i < dx; i++) {
  1904.         if (!xclear[y][x]) return 0;    /* plot point */
  1905.  
  1906.         while (error >= 0) {
  1907.         y += s2;
  1908.         error -= dxs;
  1909.         }
  1910.         x += s1;
  1911.         error += dys;
  1912.     }
  1913.     }
  1914.     return 1;
  1915. }
  1916. #endif /* VISION_TABLES */
  1917.  
  1918. /*makedefs.c*/
  1919.